package com.leigq.basaltools.bean;

import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * 响应对象。包含处理结果（Meta）和返回数据（Data）两部分，在 Controller 处理完请求后将此对象转换成 json 返回给前台。注意：
 * <ul>
 * <li>处理成功一般返回处理结果和返回数据，失败只返回处理结果。具体返回什么需看接口文档。</li>
 * </ul>
 * <p>
 *
 * @author ：leigq <br>
 * <p>
 */
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class Response<T> implements Serializable {

    private static final long serialVersionUID = -3839826779450485786L;


    /**
     * 响应代码
     */
    private Integer code;

    /**
     * 响应消息
     */
    private String msg;


    /**
     * 返回数据
     */
    private T data;


    /**
     * Instantiates a new Response.
     *
     * @param meta 元数据，包含响应码和信息。
     * @param data 返回数据
     */
    private Response(Meta meta, T data) {
        this.code = meta.getCode();
        this.msg = meta.getMsg();
        this.data = data;
    }

    /**
     * Instantiates a new Response.
     *
     * @param code 响应代码
     * @param msg  响应消息
     * @param data 返回数据
     */
    public Response(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 处理成功响应，默认响应码，默认信息，无返回数据
     *
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> success() {
        return new Response<>(MetaBase.DEF_SUCCESS, null);
    }

    /**
     * 处理成功响应，默认响应码，自定义信息，无返回数据
     *
     * @param msg 处理结果信息
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> success(String msg) {
        return new Response<>(MetaBase.DEF_SUCCESS.getCode(), msg, null);
    }


    /**
     * 处理成功响应，默认响应码，默认信息，有返回数据。
     *
     * @param data 返回数据
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> success(T data) {
        return new Response<>(MetaBase.DEF_SUCCESS, data);
    }


    /**
     * 处理成功响应，默认响应码，自定义信息，有返回数据
     *
     * @param msg  处理结果信息
     * @param data 返回数据
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> success(String msg, T data) {
        return new Response<>(MetaBase.DEF_SUCCESS.getCode(), msg, data);
    }


    /**
     * 处理成功响应，自定义响应码，自定义信息，有返回数据
     *
     * @param code 自定义响应码
     * @param msg  处理结果信息
     * @param data 返回数据
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> success(Integer code, String msg, T data) {
        return new Response<>(code, msg, data);
    }


    /**
     * 处理失败响应，返回默认(-1)响应码、默认信息，无返回数据。
     *
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> fail() {
        return new Response<>(MetaBase.DEF_FAIL, null);
    }


    /**
     * 处理失败响应，返回默认响应码、自定义信息，无返回数据。
     *
     * @param msg 处理结果信息
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> fail(String msg) {
        return new Response<>(MetaBase.DEF_FAIL.getCode(), msg, null);
    }


    /**
     * 处理失败响应，默认响应码，默认信息，有返回数据。
     *
     * @param data 返回数据
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> fail(T data) {
        return new Response<>(MetaBase.DEF_FAIL, data);
    }


    /**
     * 处理失败响应，自定义响应码，自定义信息，无返回数据
     *
     * @param <T>  the type parameter
     * @param code 自定义响应码
     * @param msg  自定义信息
     * @return 响应对象  <p>
     * @author ：leigq <br>
     * @deprecated 如果是 code，msg全都自定义的话，不建议使用此方法，更建议使用 {@link Response#fail(Meta)}，自定义MetaEnum，使整个项目保持统一
     */
    @Deprecated
    public static <T> Response<T> fail(Integer code, String msg) {
        return new Response<>(code, msg, null);
    }


    /**
     * 处理失败响应，响应元数据枚举，无返回数据
     *
     * @param <T>  the type parameter
     * @param meta the meta
     * @return the response
     */
    public static <T> Response<T> fail(Meta meta) {
        return new Response<>(meta, null);
    }


    /**
     * 处理失败响应，默认响应码，自定义信息，有返回数据
     *
     * @param msg  处理结果信息
     * @param data 返回数据
     * @return 响应对象
     * <p>
     * @author ：leigq <br>
     */
    public static <T> Response<T> fail(String msg, T data) {
        return new Response<>(MetaBase.DEF_FAIL.getCode(), msg, data);
    }


    /**
     * 处理失败响应，自定义响应码，自定义信息，有返回数据
     *
     * @param code 自定义响应码
     * @param msg  处理结果信息
     * @param data 返回数据
     * @return 响应对象
     * @author ：leigq <br>
     * @deprecated 如果是 code，msg全都自定义的话，不建议使用此方法，更建议使用 {@link Response#fail(Meta, Object)}，自定义MetaEnum，使整个项目保持统一
     */
    @Deprecated
    public static <T> Response<T> fail(Integer code, String msg, T data) {
        return new Response<>(code, msg, data);
    }


    /**
     * 处理失败响应，响应元数据枚举，无返回数据
     *
     * @param <T>  the type parameter
     * @param meta the meta
     * @param data the data
     * @return the response
     */
    public static <T> Response<T> fail(Meta meta, T data) {
        return new Response<>(meta, data);
    }

}
